// Project name:JavaRedis
// Creator:muhong
// Date time:2022/11/25,10:29 下午
// Name:AbstractNioChannel

package org.gmh.channel.nio;

import org.gmh.channel.AbstractChannel;
import org.gmh.channel.Channel;
import org.gmh.channel.DefaultChannelPipeline;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;

public abstract class AbstractNioChannel extends AbstractChannel {

    private final static Logger logger = LoggerFactory.getLogger(AbstractNioChannel.class);

    private final SelectableChannel ch;

    private final int readInterestOp;

    private SelectionKey selectionKey;

    protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
        super(parent);
        this.ch = ch;
        this.readInterestOp = readInterestOp;
        try {
            ch.configureBlocking(false);
        } catch (IOException e) {
            e.printStackTrace();
            try {
                ch.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }


    protected SelectionKey selectionKey() {
        assert selectionKey != null;
        return selectionKey;
    }

    @Override
    protected void doRegister() throws Exception {
        super.doRegister();
        Object c = this;
        selectionKey = javaChannel().register(eventLoop().selector(), this.readInterestOp, c);
    }

    @Override
    protected void doDeregister() throws Exception {
        super.doDeregister();
        logger.info("cancel connection select key!!!");
        eventLoop().cancel(selectionKey);
    }

    @Override
    public NioEventLoop eventLoop() {
        return (NioEventLoop) super.eventLoop();
    }

    @Override
    protected DefaultChannelPipeline newChannelPipeline() {
        return new DefaultChannelPipeline(this);
    }

    public SelectableChannel javaChannel() {
        return ch;
    }

    @Override
    public boolean isOpen() {
        return ch.isOpen();
    }

    @Override
    public NioUnsafe unsafe() {
        return (NioUnsafe) super.unsafe();
    }

    public interface NioUnsafe extends Unsafe {
        SelectableChannel ch();

        void read();
    }

    protected abstract class AbstractNioUnsafe extends AbstractUnsafe implements NioUnsafe {

        protected final void removeReadOp() {
            SelectionKey key = selectionKey();
            if (!key.isValid()) {
                return;
            }
            int interestOp = key.interestOps();
            if ((interestOp & readInterestOp) != 0) {
                key.interestOps(interestOp & ~readInterestOp);
            }
        }

        public final SelectableChannel ch() {
            return javaChannel();
        }
    }
}
